﻿#region License
/*

	Copyright (C) 2008 Oliver Charles, Daniel Hollander

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
*/
#endregion

using System;
using System.Drawing;
using System.Security.Permissions;
using Moebius.Core;
using SlimDX;
using SlimDX.Direct3D9;

[assembly: CLSCompliant(true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)]
[assembly: PermissionSet(SecurityAction.RequestMinimum, Name = "Nothing")]
namespace Moebius.Rendering.Direct3D9
{
    public sealed class Renderer : RenderingDevice, IDisposable
    {
        private Device direct3DDevice;
        internal Device Direct3DDevice
        {
            get { return direct3DDevice; }
        }

        protected override void Render()
        {
            Direct3DDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0);
            Direct3DDevice.BeginScene();

            foreach (Image component in Subsystem.Images)
            {
                Matrix baseMatrix = Matrix.Scaling(component.Entity.Scale, component.Entity.Scale, 1) *
                                    Matrix.RotationZ(component.Entity.Rotation) *
                                    Matrix.Translation(new Vector3(component.Entity.Position.X, component.Entity.Position.Y, 1));
                Direct3DDevice.SetTransform(TransformState.World, baseMatrix);

                component.Render();
            }

            if (Hud != null)
                Hud.Render();

            Direct3DDevice.EndScene();
            Direct3DDevice.Present();
        }

        public override void Initialize(IntPtr windowHandle, Size screenSize, GraphicsOptions graphicsOptions)
        {
            if (graphicsOptions == null) throw new ArgumentNullException("graphicsOptions");

            Direct3D.Initialize();

            /* Todo: Find the best settings we can get. */
            PresentParameters pParams = new PresentParameters();
            pParams.AutoDepthStencilFormat = Format.D24X8;
            pParams.BackBufferFormat = Format.X8R8G8B8;
            pParams.BackBufferWidth = 800;
            pParams.BackBufferHeight = 600;
            pParams.EnableAutoDepthStencil = true;
            pParams.Windowed = true;

            direct3DDevice = new Device(0, DeviceType.Hardware, windowHandle, CreateFlags.SoftwareVertexProcessing,
                                        pParams);

            base.Initialize(windowHandle, screenSize, graphicsOptions);
            InitializeDevice(graphicsOptions);

            ResourceManager = new ResourceManager(this);
            Subsystem = new RenderingSubsystem(this);
        }

        private void InitializeDevice(GraphicsOptions graphicsOptions)
        {
            Direct3DDevice.SetTransform(TransformState.Projection,
                Matrix.OrthoOffCenterLH(0, ScreenSize.Width, ScreenSize.Height, 0, graphicsOptions.ZBufferPlanes.Near,
                graphicsOptions.ZBufferPlanes.Far));

            Direct3DDevice.SetRenderState(RenderState.Lighting, false);
            Direct3DDevice.SetRenderState(RenderState.AlphaBlendEnable, true);
            Direct3DDevice.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
            Direct3DDevice.SetRenderState(RenderState.DestBlend, Blend.InvSourceAlpha);

            direct3DDevice.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Anisotropic);
            direct3DDevice.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Anisotropic);
        }

        protected override Hud.HeadsUpDisplay CreateHud()
        {
            return new HeadsUpDisplay(Direct3DDevice);
        }

        public override void RegisterResourceManager(ResourceFactory factory)
        {
            factory.RegisterResourceManager(new string[] { ".png" }, ResourceManager);
        }

		#region IDisposable Implementation
		
		private bool disposed;
		
		~Renderer()
		{
			Dispose(false);
		}

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

		private void Dispose(bool disposing)
        {
			if(!disposed) 
			{
				if(disposing)
					direct3DDevice.Dispose();
				
				disposed = true;
			}
        }

		#endregion
    }
}